package com.mlethe.library.recyclerview.viewholder;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;

import com.mlethe.library.recyclerview.listener.OnItemClickListener;
import com.mlethe.library.recyclerview.listener.OnItemLongClickListener;

import java.lang.ref.WeakReference;

/**
 * RecyclerView的ViewHolder
 * Created by Mlethe on 2018/1/11.
 */
public class ViewHolder extends RecyclerView.ViewHolder {

    /**
     * item的点击事件
     */
    private OnItemClickListener mItemClickListener;
    /**
     * item的长按事件
     */
    private OnItemLongClickListener mLongClickListener;

    /**
     * 用来存放子View减少findViewById的次数
     */
    private SparseArray<WeakReference<View>> mViews;

    public ViewHolder(@NonNull View itemView) {
        super(itemView);
        mViews = new SparseArray<>();
    }

    /**
     * dp转px
     *
     * @param context 上下问
     * @param dp      dp
     * @return px
     */
    protected int dp2px(@NonNull Context context, float dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
    }

    /**
     * 设置Visibility
     *
     * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
     * @return ViewHolder
     */
    public ViewHolder setVisibility(int visibility) {
        itemView.setVisibility(visibility);
        return this;
    }

    /**
     * 获取Visibility
     *
     * @return One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
     */
    public int getVisibility() {
        return itemView.getVisibility();
    }

    /**
     * 设置Visible
     *
     * @param visible false 隐藏，true 显示
     * @return ViewHolder
     */
    public ViewHolder setVisible(boolean visible) {
        itemView.setVisibility(visible ? View.VISIBLE : View.GONE);
        return this;
    }

    /**
     * 获取Visible
     *
     * @return false 隐藏，true 显示
     */
    public boolean getVisible() {
        return itemView.getVisibility() == View.VISIBLE;
    }

    /**
     * 设置背景
     *
     * @param background 用作背景的Drawable，或null删除背景
     * @return ViewHolder
     */
    public ViewHolder setBackground(Drawable background) {
        itemView.setBackground(background);
        return this;
    }

    /**
     * 设置背景资源
     *
     * @param resId 资源ID
     * @return ViewHolder
     */
    public ViewHolder setBackgroundResource(@DrawableRes int resId) {
        itemView.setBackgroundResource(resId);
        return this;
    }

    /**
     * 设置背景颜色
     *
     * @param color 背景颜色
     * @return ViewHolder
     */
    public ViewHolder setBackgroundColorInt(@ColorInt int color) {
        itemView.setBackgroundColor(color);
        return this;
    }

    /**
     * 设置背景颜色
     *
     * @param colorString 背景颜色（例：#RRGGBB，#AARRGGBB）
     * @return ViewHolder
     */
    public ViewHolder setBackgroundColor(String colorString) {
        return setBackgroundColorInt(Color.parseColor(colorString));
    }

    /**
     * 设置背景颜色
     *
     * @param colorId 颜色资源ID
     * @return ViewHolder
     */
    public ViewHolder setBackgroundColor(@ColorRes int colorId) {
        itemView.setBackgroundColor(ContextCompat.getColor(itemView.getContext(), colorId));
        return this;
    }

    /**
     * 设置透明度
     *
     * @param alpha 透明度【0-255】
     * @return ViewHolder
     */
    public ViewHolder setAlpha(int alpha) {
        itemView.setAlpha(alpha);
        return this;
    }

    /**
     * 通过id获取view
     *
     * @param viewId viewId
     * @param <T>    View
     * @return View
     */
    @SuppressWarnings("unchecked")
    public <T extends View> T getView(@IdRes int viewId) {
        WeakReference<View> viewReference = mViews.get(viewId);
        View view = null;
        if (viewReference != null) {
            view = viewReference.get();
        }
        if (view == null) {
            view = itemView.findViewById(viewId);
            if (view != null) {
                mViews.put(viewId, new WeakReference<>(view));
            }
        }
        return (T) view;
    }

    /**
     * 设置View宽度
     *
     * @param viewId viewId
     * @param px     px
     * @return ViewHolder
     */
    public ViewHolder setWidth(@IdRes int viewId, int px) {
        View view = getView(viewId);
        if (view != null) {
            ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
            layoutParams.width = px;
            view.setLayoutParams(layoutParams);
        }
        return this;
    }

    /**
     * 设置View宽度
     *
     * @param viewId viewId
     * @param dp     dp
     * @return ViewHolder
     */
    public ViewHolder setWidth(@IdRes int viewId, float dp) {
        View view = getView(viewId);
        if (view != null) {
            Context context = view.getContext();
            if (context != null) {
                ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
                layoutParams.width = dp2px(context, dp);
                view.setLayoutParams(layoutParams);
            }
        }
        return this;
    }

    /**
     * 设置View的高度
     *
     * @param viewId viewId
     * @param px     px
     * @return ViewHolder
     */
    public ViewHolder setHeight(@IdRes int viewId, int px) {
        View view = getView(viewId);
        if (view != null) {
            Context context = view.getContext();
            if (context != null) {
                ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
                layoutParams.height = px;
                view.setLayoutParams(layoutParams);
            }
        }
        return this;
    }

    /**
     * 设置View的高度
     *
     * @param viewId viewId
     * @param dp     dp
     * @return ViewHolder
     */
    public ViewHolder setHeight(@IdRes int viewId, float dp) {
        View view = getView(viewId);
        if (view != null) {
            Context context = view.getContext();
            if (context != null) {
                ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
                layoutParams.height = dp2px(context, dp);
                view.setLayoutParams(layoutParams);
            }
        }
        return this;
    }

    /**
     * 设置View的宽高
     *
     * @param viewId viewId
     * @param width  宽度（px）
     * @param height 高度（px）
     * @return ViewHolder
     */
    public ViewHolder setSize(@IdRes int viewId, int width, int height) {
        View view = getView(viewId);
        if (view != null) {
            Context context = view.getContext();
            if (context != null) {
                ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
                layoutParams.width = width;
                layoutParams.height = height;
                view.setLayoutParams(layoutParams);
            }
        }
        return this;
    }

    /**
     * 设置View的宽高
     *
     * @param viewId viewId
     * @param width  宽度（dp）
     * @param height 高度（dp）
     * @return ViewHolder
     */
    public ViewHolder setSize(@IdRes int viewId, float width, float height) {
        View view = getView(viewId);
        if (view != null) {
            Context context = view.getContext();
            if (context != null) {
                ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
                layoutParams.width = dp2px(context, width);
                layoutParams.height = dp2px(context, height);
                view.setLayoutParams(layoutParams);
            }
        }
        return this;
    }

    /**
     * 设置背景
     *
     * @param viewId     viewId
     * @param background 用作背景的Drawable，或null删除背景
     * @return ViewHolder
     */
    public ViewHolder setBackground(@IdRes int viewId, Drawable background) {
        View view = getView(viewId);
        if (view != null) {
            view.setBackground(background);
        }
        return this;
    }

    /**
     * 设置背景资源
     *
     * @param viewId viewId
     * @param resId  资源ID
     * @return ViewHolder
     */
    public ViewHolder setBackgroundResource(@IdRes int viewId, @DrawableRes int resId) {
        View view = getView(viewId);
        if (view != null) {
            view.setBackgroundResource(resId);
        }
        return this;
    }

    /**
     * 设置背景颜色
     *
     * @param viewId viewId
     * @param color  背景颜色
     * @return ViewHolder
     */
    public ViewHolder setBackgroundColorInt(@IdRes int viewId, @ColorInt int color) {
        View view = getView(viewId);
        if (view != null) {
            view.setBackgroundColor(color);
        }
        return this;
    }

    /**
     * 设置背景颜色
     *
     * @param viewId      viewId
     * @param colorString 背景颜色（例：#RRGGBB，#AARRGGBB）
     * @return ViewHolder
     */
    public ViewHolder setBackgroundColor(@IdRes int viewId, String colorString) {
        return setBackgroundColorInt(viewId, Color.parseColor(colorString));
    }

    /**
     * 设置背景颜色
     *
     * @param viewId  viewId
     * @param colorId 颜色资源ID
     * @return ViewHolder
     */
    public ViewHolder setBackgroundColor(@IdRes int viewId, @ColorRes int colorId) {
        View view = getView(viewId);
        if (view != null) {
            view.setBackgroundColor(ContextCompat.getColor(view.getContext(), colorId));
        }
        return this;
    }

    /**
     * 设置透明度
     *
     * @param viewId viewId
     * @param alpha  透明度【0-255】
     * @return ViewHolder
     */
    public ViewHolder setAlpha(@IdRes int viewId, int alpha) {
        View view = getView(viewId);
        if (view != null) {
            view.setAlpha(alpha);
        }
        return this;
    }

    /**
     * 设置Visibility
     *
     * @param viewId     viewId
     * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
     * @return ViewHolder
     */
    public ViewHolder setVisibility(@IdRes int viewId, int visibility) {
        View view = getView(viewId);
        if (view != null) {
            view.setVisibility(visibility);
        }
        return this;
    }

    /**
     * 获取Visibility
     *
     * @param viewId viewId
     * @return One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
     */
    public int getVisibility(@IdRes int viewId) {
        View view = getView(viewId);
        if (view != null) {
            return view.getVisibility();
        }
        return View.GONE;
    }

    /**
     * 设置Visible
     *
     * @param viewId  viewId
     * @param visible false 隐藏，true 显示
     * @return ViewHolder
     */
    public ViewHolder setVisible(@IdRes int viewId, boolean visible) {
        View view = getView(viewId);
        if (view != null) {
            view.setVisibility(visible ? View.VISIBLE : View.GONE);
        }
        return this;
    }

    /**
     * 获取Visible
     *
     * @param viewId viewId
     * @return false 隐藏，true 显示
     */
    public boolean getVisible(@IdRes int viewId) {
        View view = getView(viewId);
        if (view != null) {
            return view.getVisibility() == View.VISIBLE;
        }
        return false;
    }

    /**
     * 设置TextView文本
     *
     * @param viewId viewId
     * @param text   文本
     * @return ViewHolder
     */
    public ViewHolder setText(@IdRes int viewId, CharSequence text) {
        TextView tv = getView(viewId);
        if (tv != null) {
            tv.setText(text);
        }
        return this;
    }

    /**
     * 设置TextView文本
     *
     * @param viewId viewId
     * @param resId  String资源ID
     * @return ViewHolder
     */
    public ViewHolder setText(@IdRes int viewId, @StringRes int resId) {
        TextView tv = getView(viewId);
        if (tv != null) {
            tv.setText(resId);
        }
        return this;
    }

    /**
     * 设置TextView文本
     *
     * @param viewId viewId
     * @param value  内容
     * @return ViewHolder
     */
    public ViewHolder setTextInt(@IdRes int viewId, int value) {
        return setText(viewId, String.valueOf(value));
    }

    /**
     * 设置TextView文本
     *
     * @param viewId viewId
     * @param value  内容
     * @return ViewHolder
     */
    public ViewHolder setText(@IdRes int viewId, float value) {
        return setText(viewId, String.valueOf(value));
    }

    /**
     * 设置TextView文本
     *
     * @param viewId viewId
     * @param value  内容
     * @return ViewHolder
     */
    public ViewHolder setText(@IdRes int viewId, double value) {
        return setText(viewId, String.valueOf(value));
    }

    /**
     * 设置TextView文本
     *
     * @param viewId viewId
     * @param value  内容
     * @return ViewHolder
     */
    public ViewHolder setText(@IdRes int viewId, long value) {
        return setText(viewId, String.valueOf(value));
    }

    /**
     * 设置文字大小
     *
     * @param viewId   viewId
     * @param textSize sp
     * @return ViewHolder
     */
    public ViewHolder setTextSize(@IdRes int viewId, float textSize) {
        TextView tv = getView(viewId);
        if (tv != null) {
            tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
        }
        return this;
    }

    /**
     * 设置文字颜色
     *
     * @param viewId viewId
     * @param color  文字颜色
     * @return ViewHolder
     */
    public ViewHolder setTextColorInt(@IdRes int viewId, @ColorInt int color) {
        TextView tv = getView(viewId);
        if (tv != null) {
            tv.setTextColor(color);
        }
        return this;
    }

    /**
     * 设置文字颜色
     *
     * @param viewId  viewId
     * @param colorId 颜色资源ID
     * @return ViewHolder
     */
    public ViewHolder setTextColor(@IdRes int viewId, @ColorRes int colorId) {
        TextView tv = getView(viewId);
        if (tv != null) {
            tv.setTextColor(ContextCompat.getColor(tv.getContext(), colorId));
        }
        return this;
    }

    /**
     * 设置文字颜色
     *
     * @param viewId      viewId
     * @param colorString 文字颜色（例：#RRGGBB，#AARRGGBB）
     * @return ViewHolder
     */
    public ViewHolder setTextColor(@IdRes int viewId, String colorString) {
        return setTextColorInt(viewId, Color.parseColor(colorString));
    }

    /**
     * 设置TextView提示
     *
     * @param viewId viewId
     * @param text   内容
     * @return ViewHolder
     */
    public ViewHolder setHint(@IdRes int viewId, CharSequence text) {
        TextView tv = getView(viewId);
        if (tv != null) {
            tv.setHint(text);
        }
        return this;
    }

    /**
     * 设置TextView提示
     *
     * @param viewId viewId
     * @param resId  String资源ID
     * @return ViewHolder
     */
    public ViewHolder setHint(@IdRes int viewId, @StringRes int resId) {
        TextView tv = getView(viewId);
        if (tv != null) {
            tv.setHint(resId);
        }
        return this;
    }

    /**
     * 设置TextView提示
     *
     * @param viewId viewId
     * @param value  内容
     * @return ViewHolder
     */
    public ViewHolder setHintInt(@IdRes int viewId, int value) {
        return setHint(viewId, String.valueOf(value));
    }

    /**
     * 设置TextView提示
     *
     * @param viewId viewId
     * @param value  内容
     * @return ViewHolder
     */
    public ViewHolder setHint(@IdRes int viewId, float value) {
        return setHint(viewId, String.valueOf(value));
    }

    /**
     * 设置TextView提示
     *
     * @param viewId viewId
     * @param value  内容
     * @return ViewHolder
     */
    public ViewHolder setHint(@IdRes int viewId, double value) {
        return setHint(viewId, String.valueOf(value));
    }

    /**
     * 设置TextView提示
     *
     * @param viewId viewId
     * @param value  内容
     * @return ViewHolder
     */
    public ViewHolder setHint(@IdRes int viewId, long value) {
        return setHint(viewId, String.valueOf(value));
    }

    /**
     * 设置提示字体颜色
     *
     * @param viewId viewId
     * @param color  提示文字颜色
     * @return ViewHolder
     */
    public ViewHolder setHintTextColorInt(@IdRes int viewId, @ColorInt int color) {
        TextView tv = getView(viewId);
        if (tv != null) {
            tv.setHintTextColor(color);
        }
        return this;
    }

    /**
     * 设置文字颜色
     *
     * @param viewId  viewId
     * @param colorId 颜色资源ID
     * @return ViewHolder
     */
    public ViewHolder setHintTextColor(@IdRes int viewId, @ColorRes int colorId) {
        TextView tv = getView(viewId);
        if (tv != null) {
            tv.setHintTextColor(ContextCompat.getColor(tv.getContext(), colorId));
        }
        return this;
    }

    /**
     * 设置文字颜色
     *
     * @param viewId      viewId
     * @param colorString 提示文字颜色（例：#RRGGBB，#AARRGGBB）
     * @return ViewHolder
     */
    public ViewHolder setHintTextColor(@IdRes int viewId, String colorString) {
        return setHintTextColorInt(viewId, Color.parseColor(colorString));
    }

    /**
     * 设置是否可以点击
     *
     * @param viewId    viewId
     * @param clickable true表示视图可点击，否则为false
     * @return ViewHolder
     */
    public ViewHolder setClickable(@IdRes int viewId, boolean clickable) {
        View view = getView(viewId);
        if (view != null) {
            view.setClickable(clickable);
        }
        return this;
    }

    /**
     * 设置是否选中
     *
     * @param viewId  viewId
     * @param checked true表示选中该按钮，false表示取消选中该按钮
     * @return ViewHolder
     */
    public ViewHolder setChecked(@IdRes int viewId, boolean checked) {
        View view = getView(viewId);
        if (view instanceof CompoundButton) {
            ((CompoundButton) view).setChecked(checked);
        }
        return this;
    }

    /**
     * 设置进度
     *
     * @param viewId   viewId
     * @param progress {@link ProgressBar#getMin()} 和 {@link ProgressBar#getMax()} 之间的新进度
     * @return ViewHolder
     */
    public ViewHolder setProgress(@IdRes int viewId, int progress) {
        View view = getView(viewId);
        if (view instanceof ProgressBar) {
            ((ProgressBar) view).setProgress(progress);
        }
        return this;
    }

    /**
     * 设置ImageView显示模式
     *
     * @param viewId viewId
     * @param scaleType 所需的缩放模式
     * @return ViewHolder
     */
    public ViewHolder setScaleType(@IdRes int viewId, ImageView.ScaleType scaleType) {
        ImageView iv = getView(viewId);
        if (iv != null) {
            iv.setScaleType(scaleType);
        }
        return this;
    }

    /**
     * 设置ImageView的图片透明
     *
     * @param viewId viewId
     * @param alpha 透明度【0-255】
     * @return ViewHolder
     */
    public ViewHolder setImageAlpha(@IdRes int viewId, int alpha) {
        ImageView iv = getView(viewId);
        if (iv != null) {
            iv.setImageAlpha(alpha);
        }
        return this;
    }

    /**
     * 设置ImageView的图片
     *
     * @param viewId viewId
     * @param bitmap 要设置的位图
     * @return ViewHolder
     */
    public ViewHolder setImageBitmap(@IdRes int viewId, Bitmap bitmap) {
        ImageView iv = getView(viewId);
        if (iv != null) {
            iv.setImageBitmap(bitmap);
        }
        return this;
    }

    /**
     * 设置ImageView的图片
     *
     * @param viewId viewId
     * @param icon 保存所需图像的图标，或为空以清除内容
     * @return ViewHolder
     */
    public ViewHolder setImageDrawable(@IdRes int viewId, Icon icon) {
        ImageView iv = getView(viewId);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (iv != null) {
                iv.setImageIcon(icon);
            }
        }
        return this;
    }

    /**
     * 设置ImageView的图片
     *
     * @param viewId viewId
     * @param drawable Drawable设置，或null清除内容
     * @return ViewHolder
     */
    public ViewHolder setImageDrawable(@IdRes int viewId, Drawable drawable) {
        ImageView iv = getView(viewId);
        if (iv != null) {
            iv.setImageDrawable(drawable);
        }
        return this;
    }

    /**
     * 设置ImageView的资源
     *
     * @param viewId viewId
     * @param resId  图片资源ID
     * @return ViewHolder
     */
    public ViewHolder setImageResource(@IdRes int viewId, @DrawableRes int resId) {
        ImageView iv = getView(viewId);
        if (iv != null) {
            iv.setImageResource(resId);
        }
        return this;
    }

    /**
     * 网络图片加载
     *
     * @param viewId      viewId
     * @param imageEngine 图片加载引擎
     * @return ViewHolder
     */
    public ViewHolder setImageByUrl(@IdRes int viewId, ImageEngine imageEngine) {
        ImageView iv = getView(viewId);
        if (iv == null) {
            return this;
        }
        if (imageEngine == null) {
            return this;
        }
        imageEngine.displayImage(iv.getContext(), iv, imageEngine.getImagePath());
        return this;
    }

    /**
     * 设置View的点击事件
     *
     * @param viewId   viewId
     * @param listener 点击事件
     * @return ViewHolder
     */
    public ViewHolder setOnClickListener(@IdRes int viewId, View.OnClickListener listener) {
        View view = getView(viewId);
        if (view != null) {
            view.setOnClickListener(listener);
        }
        return this;
    }

    /**
     * 设置View的长按事件
     *
     * @param viewId   viewId
     * @param listener 长按事件
     * @return ViewHolder
     */
    public ViewHolder setOnLongClickListener(@IdRes int viewId, View.OnLongClickListener listener) {
        View view = getView(viewId);
        if (view != null) {
            view.setOnLongClickListener(listener);
        }
        return this;
    }

    /**
     * 设置条目点击事件
     */
    public <T> ViewHolder setOnItemClickListener(OnItemClickListener<T> listener) {
        mItemClickListener = listener;
        return this;
    }

    /**
     * 是否设置点击事件
     * @return
     */
    public boolean hasClickListener() {
        return mItemClickListener != null;
    }

    /**
     * 设置条目长按事件
     */
    public <T> ViewHolder setOnItemLongClickListener(OnItemLongClickListener<T> listener) {
        mLongClickListener = listener;
        return this;
    }

    /**
     * 是否设置长按事件
     * @return true 设置长按事件
     */
    public boolean hasLongClickListener() {
        return mLongClickListener != null;
    }

    /**
     * item点击事件回调
     *
     * @param view     view
     * @param item     item
     * @param position 位置
     * @param <T>      item类型
     */
    public <T> void onItemClick(@NonNull View view, T item, int position) {
        if (mItemClickListener != null) {
            mItemClickListener.onItemClick(view, item, position);
        }
    }

    /**
     * item长按事件回调
     *
     * @param view     view
     * @param item     item
     * @param position 位置
     * @param <T>      item类型
     * @return true 事件被消费，否则false
     */
    public <T> boolean onItemLongClick(@NonNull View view, T item, int position) {
        if (mLongClickListener != null) {
            return mLongClickListener.onLongClick(view, item, position);
        }
        return false;
    }

    /**
     * 图片加载，这里稍微处理得复杂一些，因为考虑加载图片的第三方可能不太一样
     * 也可以不写这个类
     */
    public static abstract class ImageEngine {
        /**
         * 图片请求地址
         */
        private String mImagePath;

        public ImageEngine(String imagePath) {
            this.mImagePath = imagePath;
        }

        public String getImagePath() {
            return mImagePath;
        }

        public abstract void displayImage(Context context, ImageView imageView, String imagePath);
    }
}
